#ifndef _FILE_H
#define _FILE_H

#include "pathparser.h"
#include <stdint.h>

typedef unsigned int FILE_SEEK_MODE; 
enum 
{
    SEEK_SET,
    SEEK_CUR,
    SEEK_END
};

typedef unsigned int FILE_MODE;
enum 
{
    FILE_MODE_READ,
    FILE_MODE_WRITE,
    FILE_MODE_APPEND,
    FILE_MODE_INVALID
};

typedef unsigned int FILE_STAT_FLAGS;
enum 
{
    FILE_STAT_READ_ONLY = 0b00000001
};

struct disk;
struct file_stat; 

/*
 *  This function shuould open a file 
 */
typedef void* (*FS_OPEN_FUNCTION)(struct disk* disk, struct path_part* path, const FILE_MODE mode); 

/*
 *  This function returns zero if the provided disk is using this filesystem
 */
typedef int (*FS_RESOLVE_FUNCTION)(struct disk* disk); 

/*
 *  This function reads data from a file and writes in to the out buffer
 */
typedef int (*FS_READ_FUNCTION)(struct disk* disk, void* private, const uint32_t size, const uint32_t nmem_blocks, char* out);

/*
 *  This function is used for moving file read cursor
 */
typedef int (*FS_SEEK_FUNCTION)(void* private, const uint32_t offset, const FILE_SEEK_MODE seek_mode); 

/*
 *  This function is used for retrieving information about file (eg. size, read only etc)
 */
typedef int (*FS_STAT_FUNCTION)(struct disk* disk, void* private, struct file_stat* stat); 

/*
 *  Function to close a file
 */
typedef int (*FS_CLOSE_FUNCTION)(void* private);


struct filesystem
{
    FS_RESOLVE_FUNCTION resolve; 
    FS_OPEN_FUNCTION open; 
    FS_READ_FUNCTION read; 
    FS_SEEK_FUNCTION seek; 
    FS_STAT_FUNCTION stat; 
    FS_CLOSE_FUNCTION close; 

    char name[20]; 
}
__attribute__((packed));

struct file_descriptor 
{
    // The descriptor index
    int index;
    struct filesystem* filesystem; 

    // Private data for internal file descriptor
    void* private; 

    // The disk that the file descriptor should be used on
    struct disk* disk;
}
__attribute__((packed));

struct file_stat
{
    FILE_STAT_FLAGS flags;
    uint32_t filesize; 
}
__attribute__((packed)); 


void fs_init(); 
void fs_insert_filesystem(struct filesystem* filesystem); 
struct filesystem* fs_resolve(struct disk* disk); 
const int fopen(const char* filename, const char* mode_str); 
const int fread(void* ptr, const uint32_t size, const uint32_t nmem_blocks, const int fd);
const int fseek(const int fd, const int offset, const FILE_SEEK_MODE whence); 
const int fstat(const int fd, struct file_stat* stat);
const int fclose(const int fd); 
#endif 